home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / mint / duftp / ftp.c < prev    next >
C/C++ Source or Header  |  1995-06-17  |  26KB  |  1,090 lines

  1. /*
  2.     DUFTP
  3. */
  4.  
  5. // FTP code
  6. // This is mostly a simplified version of the BSD FTP code....
  7.  
  8. // Most of this is indepenant of the actual DUftp user interface code.
  9. // stuff that isn't is wrapped in '#ifdef Ftp_progress'.
  10. // If Ftp_progress is defined, then these routines expect a dialog
  11. // called Ftp_progress to exist, containing (at least) two text objects
  12. // one called Ftp_operation and one called Ftp_status. If the dialog
  13. // doesn't exist, the FTP routines will use alert's for their progress
  14. // messages instead.
  15.     
  16. #include <DULIB.H>
  17. #include <TYPES.H>
  18. #include <SYS\SOCKET.H>
  19. #include <ARPA\FTP.H>
  20. #include <ARPA\TELNET.H>
  21. #include <VARARGS.H>
  22. #include <NETDB.H>
  23. #include <SETJMP.H>
  24. #include <TIME.H>
  25. #include <STAT.H>
  26. #include <SIGNAL.H>
  27. #include <ERRNO.H>
  28. #include <PORTLIB.H>
  29. #include <TIME.H>
  30. #include <CTYPE.H>
  31.  
  32. #include "ftp.h"
  33. // Omit this next include to use the routines in other programs
  34. #include "duftp_n.h"
  35. #include "globals.h"
  36.  
  37. DU_servent *sp;            // service spec for tcp/ftp
  38.  
  39. char homedir[FMSIZE];
  40.  
  41. FILE    *cin, *cout;
  42.  
  43. int connected;            // are we connected to a server ?
  44. char *hostname;            // name of the host we are connected to
  45. int type;
  46. int form;
  47. int mode;
  48. int stru;
  49. int bytesize;
  50. int cpend;
  51. int proxy;
  52. int crflag;
  53. char pasv[64];            // passive port for proxy data connection
  54.  
  55. struct    sockaddr_in hisctladdr;
  56. struct    sockaddr_in data_addr;
  57. int    data;
  58. int    abrtflag;
  59. int    ptflag;
  60. int    allbinary;
  61. struct    sockaddr_in myctladdr;
  62. off_t    restart_point;
  63. int code;
  64. int macnum;
  65.  
  66. char reply_string[BUFSIZ];        // last line of previous reply
  67.  
  68. // Signal handler for lost connections
  69. void lostpeer(int a)
  70. {
  71.     if (connected) {
  72.         if (cout != NULL) {
  73.             (void) shutdown(fileno(cout), 1+1);
  74.             (void) fclose(cout);
  75.             cout = NULL;
  76.         }
  77.         if (data >= 0) {
  78.             (void) shutdown(data, 1+1);
  79.             (void) close(data);
  80.             data = -1;
  81.         }
  82.         connected = 0;
  83.     }
  84. /*    pswitch(1);
  85.     if (connected) {
  86.         if (cout != NULL) {
  87.             (void) shutdown(fileno(cout), 1+1);
  88.             (void) fclose(cout);
  89.             cout = NULL;
  90.         }
  91.         connected = 0;
  92.     }
  93.     proxflag = 0;
  94.     pswitch(0);*/
  95. }
  96.  
  97. // Initialises all the stuff to do with the FTP routines
  98. void initialise_ftp(void)
  99. {
  100.     char *cp,*home;
  101.     struct passwd *pw = NULL;
  102.  
  103. // MiNT-NET INITIALISATION
  104.     chdir("u:/");                            // Must change to root partition here, else getservbyname will fail
  105.     sp=(DU_servent*)getservbyname("ftp","tcp");
  106.     if (sp==0)
  107.     {
  108.         form_alert(1,"[3][ ERROR: ftp/tcp: unknown service. | This probably means you haven't | installed MiNT-net correctly, as | '/etc/services' cannot be opened. ][ EXIT ]");
  109.         close_down();
  110.         exit(1);
  111.     }
  112.  
  113. // Set up the home directory
  114.     cp = getlogin();
  115.     if (cp != NULL) {
  116.         pw = getpwnam(cp);
  117.     }
  118.     if (pw == NULL)
  119.         pw = getpwuid(getuid());
  120.     if (pw != NULL) {
  121.         sprintf(homedir, "%s", pw->pw_dir);
  122.     }else{
  123.         getcwd(homedir,0);
  124.     }
  125.     home = homedir;
  126.  
  127. // Set up defaults for FTP.
  128.     type=TYPE_I;        // transferr type == binary (I know, it violates the RFC and is
  129.                         // very lazy to just use binary.....
  130.                         // **NOTE - ok, I've actually used the correct types further on.
  131.     form = FORM_N;        // form - non-print
  132.     mode = MODE_S;        // streaming mode
  133.     stru = STRU_F;        // structure=file (no record or page formatting)
  134.     bytesize = 8;        // 1 byte == 8 bits
  135.     cpend = 0;            // no pending replies
  136.     proxy = 0;            // proxy not active
  137.     crflag = 1;            // strip c.r. on ascii gets
  138.     data = -1;
  139.     abrtflag = 0;
  140.     ptflag = 0;
  141.     restart_point = 0;
  142.  
  143. // Initially, we aren't connected
  144.     connected=0;
  145.  
  146. // If we lost the ftp connection, better close down the link
  147.     signal(SIGPIPE, lostpeer);
  148. }
  149.  
  150. // Connect to peer server and auto-login, if possible.
  151.  
  152. void connect_to_server(char *server_name)
  153. {
  154.     char al[200];
  155.     char *host;
  156.     short port;
  157.  
  158.     if (connected) {
  159.         sprintf(al,"[3][ Already connected to | '%s' | - you must close this first. ][ Ok ]",hostname);
  160.         form_alert(1,al);
  161.         return;
  162.     }
  163.  
  164.     port = sp->s_port;
  165.     host = hookup(server_name, port);
  166.  
  167.     if (host)
  168.     {
  169.         connected = 1;
  170.  
  171. // Don't bother with system type enquiry on the local machine
  172.         if (strcmp(inet_ntoa(hisctladdr.sin_addr),"127.0.0.1"))
  173.         {
  174.             allbinary = 0;
  175.             type=TYPE_A;        // transferr type == ascii for sending commands
  176.  
  177.             if (send_command("SYST")==COMPLETE)    // Check remote system type. Some FTP servers don't understand
  178.             {                                    // the SYST message, so we may not always be able to tell.....
  179.                 register char *cp, c;
  180.                 cp = (char*)index(reply_string+4, ' ');
  181.                 if (cp == NULL)
  182.                     cp = (char*)index(reply_string+4, '\r');
  183.                 if (cp)
  184.                 {
  185.                     if (cp[-1] == '.')
  186.                         cp--;
  187.                     c = *cp;
  188.                     *cp = '\0';
  189.                 }
  190.  
  191. #ifdef Ftp_progress
  192.                 sprintf(al,"Remote system type is '%s'.",reply_string+4);
  193.                 set_dialog_text(Ftp_progress, Ftp_status, al);
  194.                 dialog_display(Ftp_progress);
  195. #else
  196.                 sprintf(al,"[1][ Remote system type is | '%s'.][ ok ]",reply_string+4);
  197.                 form_alert(1,al);
  198. #endif
  199.  
  200.                 if (cp) *cp = c;
  201.             }
  202.             allbinary = 1;        // This violates the RFC - but I'm not worrying about that right now
  203.             type=TYPE_I;        // so all-binary is what we get - at least you can get GIF's with it ;)
  204.         }
  205.     }
  206. }
  207.  
  208. // don't allow commands to abort at the moment
  209. /*sig_t cmdabort(int a)
  210. {
  211.     extern jmp_buf ptabort;
  212.  
  213.     printf("\n");
  214.     (void) fflush(stdout);
  215.     abrtflag++;
  216.     if (ptflag)
  217.         longjmp(ptabort,1);
  218. }*/
  219.  
  220. short send_command(char *command_to_send)
  221. {
  222.     int r;
  223. //    sig_t (*oldintr)();
  224.  
  225.     abrtflag = 0;
  226.     if (cout==NULL) {
  227.         form_alert(1,"[3][ ERROR: | No control connection for command? ][ What? ]");
  228.         return 0;
  229.     }
  230. //    oldintr = signal(SIGINT,cmdabort);
  231.     fprintf(cout, "%s\r\n", command_to_send);
  232.     (void) fflush(cout);
  233.     cpend = 1;
  234.     r = getreply(!strcmp(command_to_send, "QUIT"));
  235. //    if ((abrtflag!=0)&&((__Sigfunc)oldintr!=SIG_IGN)) (*oldintr)();
  236. //    (void) signal(SIGINT, oldintr);
  237.     return r;
  238. }
  239.  
  240. int getreply(int expecteof)
  241. {
  242.     register int c, n;
  243.     register int dig;
  244.     register char *cp;
  245.     int originalcode = 0, continuation = 0;
  246. //    sig_t (*oldintr)();
  247.     int pflag = 0;
  248.     char *pt = pasv;
  249.  
  250. //    oldintr = signal(SIGINT,cmdabort);
  251.  
  252.     for (;;) {
  253.         dig = n = 0; code = 0;
  254.         cp = reply_string;
  255.         while ((c = getc(cin)) != '\n') {
  256. /*
  257.  * For some reason the MintLib PL44's sprintf generates garbage
  258.  * with several %c's in a row, so we use fputc here. Thanks to
  259.  * Kay Roemer for reporting this! :-)
  260.  */
  261.             if (c==IAC) {     /* handle telnet commands */
  262.                 switch (c=getc(cin))
  263.                 {
  264.                     case WILL:
  265.                     case WONT:
  266.                         c = getc(cin);
  267.                         fputc(IAC, cout);
  268.                         fputc(DONT, cout);
  269.                         fputc(c, cout);
  270.                         (void) fflush(cout);
  271.                         break;
  272.                     case DO:
  273.                     case DONT:
  274.                         c = getc(cin);
  275.                         fputc(IAC, cout);
  276.                         fputc(WONT, cout);
  277.                         fputc(c, cout);
  278.                         (void) fflush(cout);
  279.                         break;
  280.                     default:
  281.                         break;
  282.                 }
  283.                 continue;
  284.             }
  285.             dig++;
  286. // End of transmission - peer has close connection
  287.             if (c == EOF) {
  288.                 if (expecteof) {
  289. //                    (void) signal(SIGINT,oldintr);
  290.                     code = 221;
  291.                     return 0;
  292.                 }
  293.                 lostpeer((int)SIG_IGN);
  294.                 form_alert(1,"[3][ Service not available, | remote server has closed | connection. ][ Bugger ]");
  295.                 return 4;
  296.             }
  297. //            if ((c != '\r')||((n=='5')&&(dig>4))) {
  298. //                (void) putchar(c);
  299. //            }
  300.             if ((dig<4)&&(isdigit(c)))
  301.                 code = code * 10 + (c - '0');
  302.             if ((!pflag)&&(code==227))
  303.                 pflag = 1;
  304.             if (((dig>4)&&(pflag==1))&&(isdigit(c)))
  305.                 pflag = 2;
  306.             if (pflag==2)
  307.             {
  308.                 if (c != '\r' && c != ')')
  309.                     *pt++ = c;
  310.                 else {
  311.                     *pt = '\0';
  312.                     pflag = 3;
  313.                 }
  314.             }
  315.             if ((dig==4)&&(c=='-'))
  316.             {
  317.                 if (continuation)
  318.                     code = 0;
  319.                 continuation++;
  320.             }
  321.             if (n==0) n = c;
  322.             if (cp<&reply_string[sizeof(reply_string)-1])
  323.                 *cp++ = c;
  324.         }
  325.         if ((continuation)&&(code!=originalcode))
  326.         {
  327.             if (originalcode==0)
  328.                 originalcode = code;
  329.             continue;
  330.         }
  331.         *cp = '\0';
  332.         if (n != '1')
  333.             cpend = 0;
  334. //        (void) signal(SIGINT,oldintr);
  335.         if ((code==421)||(originalcode==421))
  336.             lostpeer((int)SIG_IGN);
  337. //        if (((abrtflag!=0)||(cmdabort!=0))&&((__Sigfunc)oldintr!=SIG_IGN))
  338. //            (*oldintr)();
  339.         return (n-'0');
  340.     }
  341. }
  342.  
  343. char *hookup(char *host, int port)
  344. {
  345.     register DU_hostent *hp = 0;
  346.     int s,len;
  347.     char al[200];
  348.     static char hostnamebuf[80];
  349.     short con;
  350.  
  351. // First, lets get the IP address from the nameserver
  352.     bzero((char *)&hisctladdr, sizeof (hisctladdr));
  353.     hisctladdr.sin_addr.s_addr = inet_addr(host);
  354.     if (hisctladdr.sin_addr.s_addr != -1) {
  355.         hisctladdr.sin_family = AF_INET;
  356.         (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
  357.     } else {
  358.         hp = gethostbyname(host);
  359.         if (hp == NULL) {
  360.             sprintf(al,"[3][ ERROR: Unknown Host         | '%s'. ][ ok ]", host);
  361.             form_alert(1,al);
  362.             return((char *) 0);
  363.         }
  364.         hisctladdr.sin_family = hp->h_addrtype;
  365.         bcopy(hp->h_addr_list[0],
  366.             (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  367.         (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
  368.     }
  369.  
  370. #ifdef Ftp_progress
  371.     sprintf(al, "Trying '%s'.", inet_ntoa(hisctladdr.sin_addr));
  372.     set_dialog_text(Ftp_progress, Ftp_status, al);
  373.     dialog_display(Ftp_progress);
  374. #else
  375.     sprintf(al, "[1][ Connect to                 | '%s'. | Trying address '%s'.][ ok ]",host, inet_ntoa(hisctladdr.sin_addr));
  376.     form_alert(1,al);
  377. #endif
  378.  
  379. // Create control socket
  380.     hostname = hostnamebuf;
  381.     s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  382.     if (s<0)
  383.     {
  384.         form_alert(1,"[3][ ERROR: Cann't create socket. ][ ok ]");
  385.         return((char *) 0);
  386.     }
  387.  
  388.     hisctladdr.sin_port = port;
  389.  
  390. // Craigs simplified vesion of the connection procedure - doesn't retry for multiple
  391. // addresses.
  392.     con=connect(s, (struct sockaddr *)&hisctladdr, sizeof(DU_sockaddr_in));
  393.     if (con==-1)
  394.     {
  395.         (void) close(s);
  396.         sprintf(al,"[3][ ERROR: Connect failled to | '%s'. ][ ok ]",host);
  397.         form_alert(1,al);
  398.         return((char *) 0);
  399.     }
  400.  
  401.     len = sizeof (struct sockaddr_in);
  402.     if (getsockname(s, (struct sockaddr *)&myctladdr, (int*)(&len)) < 0)
  403.     {
  404.         form_alert(1,"[3][ ERROR: | Cann't get control socket name. ][ ok ]");
  405.         return((char *) 0);
  406.     }
  407.  
  408. // Open control socket for I/O operations
  409.     cin = fdopen(s, "r");
  410.     cout = fdopen(s, "w");
  411.     if ((cin==NULL)||(cout==NULL))
  412.     {
  413.         if (cin) (void) fclose(cin);
  414.         if (cout) (void) fclose(cout);
  415.         form_alert(1,"[3][ ERROR: Opening control socket failed. ][ ok ]");
  416.         return((char *) 0);
  417.     }
  418.  
  419. #ifdef Ftp_progress
  420.     sprintf(al,"Connected to server '%s'.",hostname);
  421.     set_dialog_text(Ftp_progress, Ftp_status, al);
  422.     dialog_display(Ftp_progress);
  423. #else
  424.     sprintf(al,"[1][ Connected to server | '%s'. ][ ok ]",hostname);
  425.     form_alert(1,al);
  426. #endif
  427.  
  428.     if (getreply(0)>2)      // read startup message from server
  429.     {
  430.         if (cin)
  431.             (void) fclose(cin);
  432.         if (cout)
  433.             (void) fclose(cout);
  434.         form_alert(1,"[3][ ERROR: | Server startup message is invalid, | closing connection. ][ ok ]");
  435.         return((char *) 0);
  436.     }
  437.  
  438. #ifdef SO_OOBINLINE
  439.     {
  440.         int on = 1;
  441.         setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
  442.     }
  443. #endif
  444.  
  445.     return hostname;
  446. }
  447.  
  448. // Disconnect the current session
  449.  
  450. void disconnect(void)
  451. {
  452.     if (!connected)
  453.         return;
  454.  
  455.     (void) send_command("QUIT");
  456.  
  457.     if (cout) (void) fclose(cout);
  458.     cout = NULL;
  459.     connected = 0;
  460.     data = -1;
  461.  
  462.     if (!proxy) macnum=0;
  463. }
  464.  
  465. // Login to remote host (given username & password)
  466. short login(char *user, char *pass)
  467. {
  468.     char al[80];
  469.     char tmp[80];
  470.     int n;
  471. //    int aflag = 0;
  472.  
  473. // send username
  474.     sprintf(tmp,"USER %s",user);
  475.     n = send_command(tmp);
  476.  
  477. #ifdef Ftp_progress
  478.     sprintf(al,"Logging in as '%s'.",user);
  479.     set_dialog_text(Ftp_progress, Ftp_status, al);
  480.     dialog_display(Ftp_progress);
  481. #endif
  482.  
  483. // send password
  484.     if (n == CONTINUE)
  485.     {
  486.         sprintf(tmp,"PASS %s",pass);
  487.         n = send_command(tmp);
  488.     }
  489.  
  490. // Account requested? Not supported at the moment.
  491.     if (n == CONTINUE)
  492.     {
  493. //        aflag++;
  494. //        acct = getpass("Account:");
  495. //        n = send_command("ACCT %s", acct);
  496.         disconnect();
  497.         form_alert(1,"[3][ ERROR: Accounts not supported | at the moment. ][ Disconnect ]");
  498.         return 0;
  499.     }
  500.  
  501. // Have we failled?
  502.     if (n!=COMPLETE)
  503.     {
  504.         disconnect();
  505.         form_alert(1,"[3][ ERROR: Login failled. |  Perhapes your username/password | are wrong or there are to | many users right now. ][ Disconnect ]");
  506.         return 0;
  507.     }
  508. //    if (!aflag && acct != NULL)
  509. //        (void) send_command("ACCT %s", acct);
  510.  
  511.     return 1;
  512. }
  513.  
  514. // Get a directory listing of remote files.
  515. void remote_ls(char *local, char *remote)
  516. {
  517. //    recvrequest("NLST", local, remote, "w", 0);
  518. #ifdef Ftp_progress
  519.     set_dialog_text(Ftp_progress, Ftp_operation, "Fetching remote file list.");
  520.     set_dialog_text(Ftp_progress, Ftp_status, "Sending request...");
  521.     dialog_display(Ftp_progress);
  522. #endif
  523.     type=TYPE_A;
  524.     recvrequest("LIST", local, remote, "w", 0);
  525. }
  526.  
  527. // Set current working directory on remote machine.
  528. void remote_cd(char *remote_directory)
  529. {
  530.     char cmd[200];
  531. #ifdef Ftp_progress
  532.     set_dialog_text(Ftp_progress, Ftp_operation, "Changing remote directory.");
  533.     set_dialog_text(Ftp_progress, Ftp_status, "Sending CWD command...");
  534.     dialog_display(Ftp_progress);
  535. #endif
  536.     type=TYPE_A;
  537.     sprintf(cmd,"CWD %s", remote_directory);
  538.     if (send_command(cmd) == ERROR && code == 500)
  539.     {
  540. #ifdef Ftp_progress
  541.         set_dialog_text(Ftp_progress, Ftp_status, "CWD didn't work - trying XCWD instead...");
  542.         dialog_display(Ftp_progress);
  543. #endif
  544.         sprintf(cmd,"XCWD %s", remote_directory);
  545.         (void) send_command(cmd);
  546.     }
  547. }
  548.  
  549. // Get a file from the remote server
  550. void remote_get(char *local, char *remote)
  551. {
  552. #ifdef Ftp_progress
  553.     char msg[100];
  554.     sprintf(msg,"Getting file '%s'.",remote);
  555.     set_dialog_text(Ftp_progress, Ftp_operation, msg);
  556.     set_dialog_text(Ftp_progress, Ftp_status, "Sending request...");
  557.     dialog_display(Ftp_progress);
  558. #endif
  559.     type=TYPE_I;
  560.     recvrequest("RETR", local, remote, "w", 0);
  561.     restart_point = 0;
  562. }
  563.  
  564. // Get remote current working directory.
  565. char *remote_pwd(void)
  566. {
  567.     char rtn[BUFSIZ],*d;
  568.     
  569. #ifdef Ftp_progress
  570.     set_dialog_text(Ftp_progress, Ftp_operation, "Getting remote pwd.");
  571.     set_dialog_text(Ftp_progress, Ftp_status, "Sending PWD command...");
  572.     dialog_display(Ftp_progress);
  573. #endif
  574.     type=TYPE_A;
  575.     if (send_command("PWD") == ERROR && code == 500)
  576.     {
  577. #ifdef Ftp_progress
  578.         set_dialog_text(Ftp_progress, Ftp_status, "PWD didn't work - trying XPWD...");
  579.         dialog_display(Ftp_progress);
  580. #endif
  581.         if (send_command("XPWD")!=COMPLETE)
  582.             return NULL;
  583.     }
  584.     
  585.     d=reply_string+5;
  586.     sscanf(d,"%s",rtn);
  587.     rtn[strlen(rtn)-1]='\0';
  588.     sprintf(reply_string,"%s",rtn);
  589.     return reply_string;
  590. }
  591.  
  592. // Ho Hum - some rather unstructured & obscure abort recieve code from BSD here
  593.  
  594. jmp_buf    recvabort;
  595.  
  596. void abortrecv(int a)
  597. {
  598.  
  599. //    mflag = 0;
  600.     abrtflag = 0;
  601.     printf("\n");
  602.     (void) fflush(stdout);
  603.     longjmp(recvabort, 1);
  604. }
  605.  
  606. typedef int (*recvreq_close_fn)(FILE *f);
  607.  
  608. void recvrequest(char *cmd, char *local, char *remote, char *mode, short
  609. printnames)
  610. {
  611.     char cmdbuf[200];
  612.     char al[200];
  613.     FILE *fout, *din = 0;
  614.     recvreq_close_fn closefunc;
  615.     __Sigansi oldintr, oldintp;
  616.     int is_retr, tcrflag, nfnd, bare_lfs = 0;
  617.     char msg;
  618.     static char *buf;
  619.     static int bufsize;
  620.     long bytes = 0;
  621.     fd_set mask;
  622.     int cg_comret;
  623.     register int c, d;
  624.     struct stat st;
  625.     extern char *malloc();
  626.  
  627.     is_retr = strcmp(cmd, "RETR") == 0;
  628. //    if (proxy && is_retr) {
  629. //        proxtrans(cmd, local, remote);
  630. //        return;
  631. //    }
  632.     closefunc = NULL;
  633.     oldintr = NULL;
  634.     oldintp = NULL;
  635.     tcrflag = !crflag && is_retr;
  636.     if (setjmp(recvabort)) {
  637.         while (cpend) {
  638.             (void) getreply(0);
  639.         }
  640.         if (data >= 0) {
  641.             (void) close(data);
  642.             data = -1;
  643.         }
  644.         if (oldintr)
  645.             (void) signal(SIGINT, oldintr);
  646.         code = -1;
  647.         return;
  648.     }
  649.  
  650.     oldintr = signal(SIGINT, abortrecv);
  651.  
  652.     if (*local!='-')
  653.     {
  654.         if (access(local, 2) < 0) {
  655.             sprintf(al,"[3][ FILE TRANSFER: | Cann't access destination file | '%s'. ][ cancel ]",local);
  656.             form_alert(1,al);
  657.             (void) signal(SIGINT, oldintr);
  658.             code = -1;
  659.             return;
  660.         }
  661.     }
  662.     if (initconn()) {
  663.         form_alert(1,"[3][ FILE TRANSFER: | Cann't initiate data connection. ][ cancel ]");
  664.         (void) signal(SIGINT, oldintr);
  665.         code = -1;
  666.         return;
  667.     }
  668.     if (setjmp(recvabort))
  669.         goto abort;
  670.  
  671.     cg_comret=0;
  672.     switch (type)            // Simplified transfer type selection, 'coz I'm buggered if
  673.     {                        // I could persuade the BSD version to work.
  674.         case TYPE_A:
  675.             cg_comret=send_command("TYPE A");
  676.             break;
  677.         case TYPE_I:
  678.             cg_comret=send_command("TYPE I");
  679.             break;
  680.         case TYPE_E:
  681.             cg_comret=send_command("TYPE E");
  682.             break;
  683.         case TYPE_L:        // What the hell is tenex mode anyway?
  684.             return;
  685.             break;
  686.     }
  687.  
  688.     if (cg_comret!=COMPLETE)    // Did we get the acknowledgment back from the TYPE command?
  689.     {
  690.         form_alert(1,"[3][ FILE TRANSFER: | Problem setting transfer type. ][ cancel ]");
  691.         return;
  692.     }
  693.     
  694.     if (remote)                    // Command specified a remote file / extra parameter?
  695.     {
  696.         sprintf(cmdbuf,"%s %s", cmd, remote);    // Tell remote command & file.
  697.         send_command(cmdbuf);
  698.     }else{                        // Just send a command, not remote file, but it will 
  699.          send_command(cmd);        // reply with data....
  700.      }
  701.  
  702.     din = dataconn("rb");        // Open the data channel
  703.  
  704.     if ((din->_flag&_IOBIN)!=_IOBIN)    // Quick check to make sure we got a binary file
  705.     {
  706.         _binmode(fileno(din));
  707.         if ((din->_flag&_IOBIN)==_IOBIN)
  708.             form_alert(1,"[3][ FILE TRANSFER: | Cann't open socket as binary. ][ cancel ]");
  709.     }
  710.  
  711. #ifdef Ftp_progress
  712.     set_dialog_text(Ftp_progress, Ftp_status, "Initiating data connection.");
  713.     dialog_display(Ftp_progress);
  714. #else
  715.     form_alert(1,"[3][ FILE TRANSFER: | Initiating data connection. ][ ok ]");
  716. #endif
  717.  
  718.     if (din == NULL)
  719.         goto abort;
  720.  
  721.     if (*local=='-')
  722.     {
  723.         fout = stdout;
  724.     } else {
  725.         fout = fopen(local, "wb");
  726.         if (fout == NULL) {
  727.             sprintf(al,"[3][ FILE TRANSFER: | Cann't open local file | '%s'. ][ ok ]",local);
  728.             form_alert(1,al);
  729.             goto abort;
  730.         }
  731.         closefunc = fclose;
  732.     }
  733.     if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
  734.         st.st_blksize = BUFSIZ;
  735.     if (st.st_blksize > bufsize) {
  736.         if (buf)
  737.             (void) free(buf);
  738.         buf = malloc((unsigned)st.st_blksize);
  739.         if (buf == NULL) {
  740.             form_alert(1,"[3][ FILE TRANSFER: | Cann't allocate memory for transfer. | Looks like we're out of RAM :( ][ bugger ]");
  741.             bufsize = 0;
  742.             goto abort;
  743.         }
  744.         bufsize = st.st_blksize;
  745.     }
  746.  
  747.     switch (type)
  748.     {
  749.         case TYPE_I:
  750.         case TYPE_L:
  751.             if ((restart_point)&&(
  752.                 lseek(fileno(fout), (long) restart_point, L_SET) < 0)) {
  753.                 //perror(local);
  754.                 if (closefunc != NULL)
  755.                     (*closefunc)(fout);
  756.                 return;
  757.             }
  758.             errno = d = 0;
  759. #ifdef Ftp_progress
  760.             set_dialog_text(Ftp_progress, Ftp_status, "Binary: Started file transfer.");
  761.             dialog_display(Ftp_progress);
  762. #endif
  763.  
  764.             while ((c = read(fileno(din), buf, bufsize)) > 0)
  765.             {
  766.                 if ((d = write(fileno(fout), buf, c)) != c)        // Short write?
  767.                     break;
  768.                 
  769.                 bytes += c;
  770.     
  771. #ifdef Ftp_progress
  772.                 if ((bytes%250==0)||(c>250))
  773.                 {
  774.                     sprintf(al,"Binary: transferred %d bytes.",bytes);
  775.                     set_dialog_text(Ftp_progress, Ftp_status, al);
  776.                     dialog_display(Ftp_progress);
  777.                     if (PollEvent(10)==mev_STOPTRANSFER)    // poll for 10ms for events from the GUI
  778.                         goto abort;
  779.                 }
  780. #endif
  781.             }
  782.  
  783.             if (c < 0)
  784.             {
  785.                 bytes = -1;
  786.             }
  787.             if (d < c)
  788.             {
  789.                 sprintf(al,"[3][ FILE TRANSFER: | Short write | '%s'. | Looks like we're out of disc | space for incoming files. ][ bugger ]",local);
  790.                 form_alert(1,al);
  791.             }
  792.             break;
  793.  
  794.         case TYPE_A:
  795.             if (restart_point)
  796.             {
  797.                 register int i, n, c;
  798.     
  799.                 if (fseek(fout, 0L, L_SET) < 0)
  800.                     goto done;
  801.                 n = restart_point;
  802.                 i = 0;
  803.                 while (i++ < n)
  804.                 {
  805.                     if ((c=getc(fout)) == EOF)
  806.                         goto done;
  807.                     if (c == '\n')
  808.                         i++;
  809.                 }
  810.                 if (fseek(fout, 0L, L_INCR) < 0)
  811.                 {
  812. done:
  813.                     if (closefunc != NULL)
  814.                         (*closefunc)(fout);
  815.                     return;
  816.                 }
  817.             }
  818.             
  819.             while ((c = getc(din)) != EOF)
  820.             {
  821.                 if (c == '\n')
  822.                     bare_lfs++;
  823.                 while (c == '\r')
  824.                 {
  825.                     bytes++;
  826.                     if ((c = getc(din)) != '\n' || tcrflag)
  827.                     {
  828.                         if (ferror(fout))
  829.                             goto break2;
  830.                         (void) putc('\r', fout);
  831.                         if (c == '\0')
  832.                         {
  833.                             bytes++;
  834.                             goto contin2;
  835.                         }
  836.                         if (c == EOF)
  837.                             goto contin2;
  838.                     }
  839. #ifdef Ftp_progress
  840.                     if (bytes%250<10)
  841.                     {
  842.                         sprintf(al,"ASCII: transferred %d bytes.",bytes);
  843.                         set_dialog_text(Ftp_progress, Ftp_status, al);
  844.                         dialog_display(Ftp_progress);
  845.                         if (PollEvent(10)==mev_STOPTRANSFER)    // poll for 10ms for events from the GUI
  846.                             goto abort;
  847.                     }
  848. #endif
  849.                 }
  850.                 (void) putc(c, fout);
  851.                 bytes++;
  852.     contin2:    ;
  853.             }
  854. break2:
  855. //            if (bare_lfs) {
  856. //                form_alert(1, "[1][ WARNING! | Bare linefeeds received in ASCII | mode - file may not have | transferred correctly. ][ ok ]");
  857. //            }
  858.             if (ferror(din)) {
  859.                 bytes = -1;
  860.             }
  861.             break;
  862.     }
  863.     if (closefunc != NULL)
  864.         (*closefunc)(fout);
  865.     (void) signal(SIGINT, oldintr);
  866.     if (oldintp)
  867.     (void) signal(SIGPIPE, oldintp);
  868.     (void) fclose(din);
  869.     (void) getreply(0);
  870. //    if (bytes > 0 && is_retr)
  871. //    {
  872. //        report_bytes_transferred("received", bytes);
  873. //    }
  874.  
  875.     return;
  876. abort:
  877.  
  878. /* abort using RFC959 recommended IP,SYNC sequence  */
  879.  
  880. //    (void) gettimeofday(&stop, (struct timezone *)0);
  881.     if (oldintp)
  882.         (void) signal(SIGPIPE, oldintr);
  883.     (void) signal(SIGINT,SIG_IGN);
  884.     if (!cpend) {
  885.         code = -1;
  886.         (void) signal(SIGINT,oldintr);
  887.         return;
  888.     }
  889.  
  890. #ifdef __MINT__
  891.     fputc(IAC, cout);
  892.     fputc(IP, cout);
  893. #else
  894.     fprintf(cout,"%c%c",IAC,IP);
  895. #endif
  896.     (void) fflush(cout);     msg = IAC;
  897. /* send IAC in urgent mode instead of DM because UNIX places oob mark */
  898. /* after urgent byte rather than before as now is protocol            */
  899.     if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
  900.         form_alert(1,"[3][ ABORT.                   ][ ok ]");
  901.     }
  902.     fprintf(cout,"%cABOR\r\n",DM);
  903.     (void) fflush(cout);
  904.     FD_ZERO(&mask);
  905.     FD_SET(fileno(cin), &mask);
  906.     if (din)
  907.     {
  908.         FD_SET(fileno(din), &mask);
  909.     }
  910.     if ((nfnd = empty(&mask,10)) <= 0) {
  911.         if (nfnd < 0) {
  912.             form_alert(1,"[3][ ABORT.                ][ ok ]");
  913.         }
  914.         code = -1;
  915.         lostpeer(0);
  916.     }
  917.     if (din && FD_ISSET(fileno(din), &mask)) {
  918.         while ((c = read(fileno(din), buf, bufsize)) > 0);
  919.     }
  920.     if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nice style abort */
  921.         if (data >= 0) {
  922.             (void) close(data);
  923.             data = -1;
  924.         }
  925.         (void) getreply(0);
  926.     }
  927.     (void) getreply(0);
  928.     code = -1;
  929.     if (data >= 0) {
  930.         (void) close(data);
  931.         data = -1;
  932.     }
  933.     if (closefunc != NULL && fout != NULL)
  934.         (*closefunc)(fout);
  935.     if (din)
  936.         (void) fclose(din);
  937.     if (bytes > 0)
  938.     {
  939.         report_bytes_transferred("received", bytes);
  940.     }
  941.     (void) signal(SIGINT,oldintr);
  942. }
  943.  
  944. char *gunique(char *local)
  945. {
  946.     static char new[FMSIZE];
  947.     char *cp = (char*)rindex(local, '/');
  948.     int d, count=0;
  949.     char ext = '1';
  950.  
  951.     if (cp)
  952.         *cp = '\0';
  953.     d = access(cp ? local : ".", 2);
  954.     if (cp)
  955.         *cp = '/';
  956.     if (d < 0) {
  957.         return((char *) 0);
  958.     }
  959.     (void) strcpy(new, local);
  960.     cp = new + strlen(new);
  961.     *cp++ = '.';
  962.     while (!d) {
  963.         if (++count == 100)
  964.         {
  965.             form_alert(1,"[3][ ERROR: | Cann't find unique file name. ][ ok ]");
  966.             return((char *) 0);
  967.         }
  968.         *cp++ = ext;
  969.         *cp = '\0';
  970.         if (ext == '9')
  971.             ext = '0';
  972.         else
  973.             ext++;
  974.         if ((d = access(new, 0)) < 0)
  975.             break;
  976.         if (ext != '0')
  977.             cp--;
  978.         else if (*(cp - 2) == '.')
  979.             *(cp - 1) = '1';
  980.         else {
  981.             *(cp - 2) = *(cp - 2) + 1;
  982.             cp--;
  983.         }
  984.     }
  985.     return(new);
  986. }
  987.  
  988. // Need to start a listen on the data channel
  989. // before we send the command, otherwise the
  990. // server's connect may fail.
  991.  
  992. int sendport = -1;
  993.  
  994. short initconn(void)
  995. {
  996.     char cmdbuf[200];
  997.     register char *p, *a;
  998.     int result, len, tmpno = 0;
  999.     int on = 1;
  1000.  
  1001. noport:
  1002.     data_addr = myctladdr;
  1003.     if (sendport)
  1004.         data_addr.sin_port = 0;    /* let system pick one */
  1005.     if (data != -1)
  1006.         (void) close (data);
  1007.     data = socket(AF_INET, SOCK_STREAM, 0);
  1008.     if (data < 0) {
  1009.         form_alert(1,"[3][ ERROR: | Cann't create Data socket. ][ ok ]");
  1010.         if (tmpno)
  1011.             sendport = 1;
  1012.         return (1);
  1013.     }
  1014.     if (!sendport)
  1015.         if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
  1016.             form_alert(1,"[3][ ERROR: | Cann't reuse Data socket address. ][ ok ]");
  1017.             goto bad;
  1018.         }
  1019.     if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
  1020.         form_alert(1,"[3][ ERROR: | Cann't bind Data socket. ][ ok ]");
  1021.         goto bad;
  1022.     }
  1023.     len = sizeof (data_addr);
  1024.     if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
  1025.         form_alert(1,"[3][ ERROR: | Cann't get Data socket name. ][ ok ]");
  1026.         goto bad;
  1027.     }
  1028.     if (listen(data, 1) < 0)
  1029.         form_alert(1,"[3][ ERROR: | ftp:listen ? ][ ok ]");
  1030.     if (sendport) {
  1031.         a = (char *)&data_addr.sin_addr;
  1032.         p = (char *)&data_addr.sin_port;
  1033. #define    UC(b)    (((int)b)&0xff)
  1034.         sprintf(cmdbuf,"PORT %d,%d,%d,%d,%d,%d",
  1035.               UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
  1036.               UC(p[0]), UC(p[1]));
  1037.         result =
  1038.             send_command(cmdbuf);
  1039.             if (result == ERROR && sendport == -1) {
  1040.             sendport = 0;
  1041.             tmpno = 1;
  1042.             goto noport;
  1043.         }
  1044.         return (result != COMPLETE);
  1045.     }
  1046.     if (tmpno)
  1047.         sendport = 1;
  1048.     return (0);
  1049. bad:
  1050.     (void) close(data), data = -1;
  1051.     if (tmpno)
  1052.         sendport = 1;
  1053.     return (1);
  1054. }
  1055.  
  1056. void report_bytes_transferred(char *direction, long bytes)
  1057. {
  1058.     char al[200];
  1059.  
  1060.     sprintf(al,"[1][ TRANSFER: | %ld bytes %s. ][ ok ]", bytes, direction);
  1061.     form_alert(1,al);
  1062. }
  1063.  
  1064. int empty(fd_set *mask, int sec)
  1065. {
  1066.     struct timeval t;
  1067.  
  1068.     t.tv_sec = (long) sec;
  1069.     t.tv_usec = 0;
  1070.     return(select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
  1071. }
  1072.  
  1073. FILE *dataconn(char *mode)
  1074. {
  1075.     struct sockaddr_in from;
  1076.     int s, fromlen = sizeof (struct sockaddr_in);
  1077.  
  1078.     s = accept(data, (struct sockaddr *) &from, &fromlen);
  1079.     if (s < 0) {
  1080.         form_alert(1,"[3][ ERROR: | ftp:accept() ? ][ ok ]");
  1081.         (void) close(data), data = -1;
  1082.         return (NULL);
  1083.     }
  1084.     (void) close(data);
  1085.     data = s;
  1086.     return (fdopen(data, mode));
  1087. }
  1088.  
  1089.  
  1090.